package cn.js.sangu.unitStore.service.async;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import cn.js.sangu.unitStore.common.constant.SysInfo;
import cn.js.sangu.unitStore.common.exception.ServiceException;
import cn.js.sangu.unitStore.dto.FileListDTO;
import cn.js.sangu.unitStore.dto.MsgDTO;
import cn.js.sangu.unitStore.entity.FileNas;
import cn.js.sangu.unitStore.entity.UtilsEntity;
import cn.js.sangu.unitStore.service.FileService;
import cn.js.sangu.unitStore.service.process.ExcelProcessService;
import cn.js.sangu.unitStore.service.update.UtilsUpdateService;
import cn.js.sangu.unitStore.utils.LinsUtil;
import cn.js.sangu.unitStore.utils.PDFUtil;
import cn.js.sangu.unitStore.websocket.WebSocketService;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class UtilsAsyncService {

    private final FileService fileService;
    private final ExcelProcessService excelProcessService;
    private final UtilsUpdateService utilsUpdateService;
    private final WebSocketService wService;

    // @Autowired
    public UtilsAsyncService(
            FileService fileService,
            ExcelProcessService excelProcessService,
            UtilsUpdateService utilsUpdateService,
            WebSocketService wService) {
        this.fileService = fileService;
        this.excelProcessService = excelProcessService;
        this.utilsUpdateService = utilsUpdateService;
        this.wService = wService;
    }

    static final String ROOT_PATH = System.getProperty("user.dir") + File.separator + "files";
    static String today = cn.hutool.core.date.DateUtil.today();
    static String folderRootPath = ROOT_PATH + File.separator + today + File.separator;

    // 加工文件
    @Async("taskExecutor") // 异步方法
    public void executiveProcess(UtilsEntity utilsEntity, Boolean autoCode, Long userId) {
        try {
            long start = System.currentTimeMillis();
            FileNas fileNas = new FileNas();
            String filePath = "";
            String workName = utilsEntity.getWorkName();
            ObjectMapper mapper = new ObjectMapper();
            // 转换取出 文件列表
            List<FileListDTO> dtoList = mapper.convertValue(utilsEntity.getFileListJson(),
                    mapper.getTypeFactory().constructCollectionType(List.class, FileListDTO.class));

            if ("合并PDF".equals(workName)) {
                filePath = handleMergePDF(dtoList, fileNas, userId);
            } else if ("文件转链接".equals(workName)) {
                throw new ServiceException("功能正在开发中……");
            } else if ("Excel清单筛选".equals(workName)) {
                filePath = handleExcelFilter(dtoList, fileNas, autoCode, userId);
            } else {
                throw new ServiceException("功能正在开发中……");
            }
            // 在异步里更新Util表的加工后路径
            utilsEntity.setAttachType(filePath);
            // 设置状态为加工成功
            utilsEntity.setState(SysInfo.ProcessStatusSuccess);
            long end = System.currentTimeMillis();
            log.info("{} ：UtilsAsyncService.executiveProcess 异步方法用时{}毫秒", Thread.currentThread().getName(),
                    end - start);
            Long ms = end - start;
            if (ms < 1000) {
                utilsEntity.setTakeTime(ms + "毫秒");
            } else {
                Long s = ms / 1000;
                if (s < 600) {
                    utilsEntity.setTakeTime(s + "秒");
                } else {
                    utilsEntity.setTakeTime(s / 60 + "分钟");
                }
            }
            if (!utilsUpdateService.updateUtilsEntity(utilsEntity)) {
                throw new ServiceException("Utils加工后文件路径更新失败！请联系管理员");
            }
            // 保存文件记录
            if (!fileService.save(fileNas)) {
                throw new ServiceException("Utils-加工后文件记录保存失败！请联系管理员");
            }
            // 发送通知
            log.info("工具任务处理完成，结果文件路径：{}", filePath);
            wService.sendMsg(new MsgDTO(userId.toString(), "success", "工具任务处理完成"));
        } catch (Exception e) {
            log.error("文件处理过程中发生异常", e);
            // 设置状态为加工失败
            utilsEntity.setState(SysInfo.ProcessStatusFail);
            wService.sendMsg(new MsgDTO(userId.toString(), "error", "工具任务处理完成"));
            if (!utilsUpdateService.updateUtilsEntity(utilsEntity)) {
                log.error("更新Utils记录状态为加工失败时失败", e);
            }
        }
    }

    private String handleMergePDF(List<FileListDTO> dtoList, FileNas fileNas, Long userId) throws ServiceException {
        if (dtoList.size() < 2) {
            throw new ServiceException("不足两个文件，无需合并");
        }
        // 准备存储 文件路径
        List<String> filePaths = new ArrayList<>();
        ObjectMapper mapper = new ObjectMapper();
        for (FileListDTO dto : dtoList) {
            Object data = dto.getResponse().getData();
            FileNas res = mapper.convertValue(data, new TypeReference<FileNas>() {
            });
            filePaths.add(res.getFilePath());
        }
        String fileName = cn.hutool.core.date.DateUtil.format(new java.util.Date(), "yyyyMMddHHmmssSSS") + "合并PDF.pdf";
        String filePath = folderRootPath + fileName;
        // 执行合并
        PDFUtil.mergeToPDF(filePaths, filePath);
        fileNas.setFileName(fileName);
        fileNas.setFileType(cn.js.sangu.unitStore.common.constant.SysInfo.ToolGeneration); // 工具生成
        fileNas.setFilePath(filePath);
        fileNas.setUserId(userId.intValue());
        File file = new File(filePath);
        if (file.exists() && file.isFile()) {
            // 获取文件大小（以字节为单位）
            fileNas.setFileSize(LinsUtil.computeFileSize(file.length()));
        } else {
            throw new ServiceException("合并PDF后找不到加工文件");
        }
        return filePath;
    }

    // 处理Excel清单筛选
    private String handleExcelFilter(List<FileListDTO> dtoList, FileNas fileNas, Boolean autoCode, Long userId)
            throws ServiceException {
        ObjectMapper mapper = new ObjectMapper();
        // 检查文件列表是否为空
        if (dtoList == null || dtoList.isEmpty()) {
            throw new ServiceException("Excel文件列表不能为空");
        }
        // 获取Excel文件路径
        String excelPath = mapper.convertValue(dtoList.get(0).getResponse().getData(), FileNas.class).getFilePath();
        // 调用Excel处理服务，保存原始数据到数据库
        String filePath = excelProcessService.dataProcess(excelPath, autoCode, userId);
        File resultFile = new File(filePath);
        if (resultFile.exists() && resultFile.isFile()) {
            fileNas.setFileSize(LinsUtil.computeFileSize(resultFile.length()));
        } else {
            throw new ServiceException("Excel处理结果文件生成失败");
        }
        // 生成处理结果文件
        fileNas.setFileName(resultFile.getName());
        fileNas.setFileType(SysInfo.ToolGeneration);
        fileNas.setFilePath(filePath);
        // 补充其他属性
        fileNas.setDownCount(0); // 初始下载次数设为 0
        fileNas.setParId(null); // 假设没有父级 id
        fileNas.setParPath(null); // 假设没有父级路径
        fileNas.setRemark("工具生成"); // 添加备注
        fileNas.setUserId(userId.intValue());
        return filePath;
    }

    public void test() {
        excelProcessService.test();
    }

    public void testWs(String uid) {
        wService.sendMsg(new MsgDTO(uid, "test", "工具任务测试消息"));
        // utilsWsHandler.handleTestMessage(new MsgDTO(uid,"test","工具任务测试消息"));
    }

}